package org.tote.dao;

import java.util.List;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Repository;
import org.tote.dao.util.DaoUtils;
import org.tote.model.User;

@Repository
public class UserDaoImpl implements UserDao {

	@Autowired
	private SessionFactory sessionFactory;

	@Override
	public void save(User user) {
		sessionFactory.getCurrentSession().save(user);
	}

	@Override
	public void update(User user) {
		sessionFactory.getCurrentSession().update(user); //merge(user);
	}

	@Override
	public void remove(User user) {
		sessionFactory.getCurrentSession().delete(user);
	}

	public User getById(Long id) {
		return (User) sessionFactory.getCurrentSession().get(User.class, id);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<User> getAllUsers() {
		return sessionFactory.getCurrentSession().createQuery("FROM User").list();
	}

	@Override
	public void removeList(List<String> nameList) {
		StringBuilder query = new StringBuilder("delete User user where user.username in ");
		query.append(DaoUtils.generateIdList(nameList));
		sessionFactory.getCurrentSession().createQuery(query.toString()).executeUpdate();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<User> getUserList(List<String> nameList) {
		StringBuilder query = new StringBuilder("From User user where user.username in ");
		query.append(DaoUtils.generateIdList(nameList));
		return sessionFactory.getCurrentSession().createQuery(query.toString()).list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<User> getUserListExcluding(List<String> nameList) {
		StringBuilder query = new StringBuilder("From User user where user.id not in ");
		query.append(DaoUtils.generateIdList(nameList));
		return sessionFactory.getCurrentSession().createQuery(query.toString()).list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<User> getFilteredUsersExcludingPage(List<Long> excludeList, int page, int limit,
			String usersFilter) {
		// One additional row to check if there are more rows
		return sessionFactory.getCurrentSession().createQuery(getUsersExcludingWhere(excludeList))
				.setFirstResult(page * limit).setMaxResults(limit + 1)
				.setParameter("userFilter", '%' + usersFilter + '%').list();
	}

	@Override
	public int getFilteredUsersExcludingCount(List<Long> excludeList, String usersFilter) {
		return Integer.valueOf(sessionFactory.getCurrentSession()
				.createQuery("SELECT count(id) " + getUsersExcludingWhere(excludeList))
				.setParameter("userFilter", '%' + usersFilter + '%').uniqueResult().toString());
	}

	private String getUsersExcludingWhere(List<Long> excludeList) {
		return "FROM User u WHERE u.id NOT IN " + DaoUtils.generateIdList(excludeList)
				+ " AND u.name LIKE :userFilter";
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<User> getFilteredUsersPage(int page, int limit, String usersFilter) {
		// One additional row to check if there are more rows
		return sessionFactory.getCurrentSession().createQuery(getFilteredUsersWhere())
				.setParameter("userFilter", '%' + usersFilter + '%').setFirstResult(page * limit)
				.setMaxResults(limit + 1).list();
	}

	@Override
	@Cacheable("userCount")
	public int getFilteredUsersCount(String usersFilter) {
		return Integer.valueOf(sessionFactory.getCurrentSession()
				.createQuery("SELECT count(id) " + getFilteredUsersWhere())
				.setParameter("userFilter", '%' + usersFilter + '%').uniqueResult().toString());
	}

	private String getFilteredUsersWhere() {
		return "FROM User WHERE fullnameRu LIKE :userFilter OR fullnameEn LIKE :userFilter";
	}

	@Override
	public User findByLogin(String login) {
		return (User) sessionFactory.getCurrentSession()
				.createQuery("FROM User user where user.username=:username")
				.setString("username", login).uniqueResult();
	}

	@Override
	public User findByToken(String token) {
		return (User) sessionFactory.getCurrentSession()
				.createQuery("FROM User where token=:token").setString("token", token)
				.uniqueResult();
	}

	@Override
	public User findByOpenId(String openId) {
		return (User) sessionFactory.getCurrentSession()
				.createQuery("FROM User user where user.openId=:openId")
				.setString("openId", openId).uniqueResult();
	}

}